using FytSoa.Application.Erp.Param;
using FytSoa.Common.Enum;
using FytSoa.Common.Extensions;
using FytSoa.Domain.Erp;
using FytSoa.Sugar;
using FytSoa.Common.Utils;
using FytSoa.Common.Param;
using FytSoa.Common.Result;
using FytSoa.Domain.Crm;
using Mapster;
using Masuit.Tools.Reflection;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;

namespace FytSoa.Application.Erp;

/// <summary>
/// erp-产品出库服务接口
/// </summary>
[ApiExplorerSettings(GroupName = "v9")]
public class ErpOutstockService : IApplicationService 
{
    private readonly SugarRepository<ErpOutstock> _thisRepository;
    private readonly SugarRepository<ErpOutstockProduct> _outStockProductRepository;
    private readonly SugarRepository<ErpPurchaseReturn> _returnRepository;
    private readonly SugarRepository<ErpProduceOrder> _produceOrderRepository;
    private readonly SugarRepository<CrmProject> _projectRepository;
    private readonly ErpFlowUseService _flowUseService;
    private readonly ErpOperateLogService _operateLogService;

    public ErpOutstockService(SugarRepository<ErpOutstock> thisRepository
    ,SugarRepository<ErpOutstockProduct> outStockProductRepository
    ,SugarRepository<ErpPurchaseReturn> returnRepository
    ,SugarRepository<ErpProduceOrder> produceOrderRepository
    ,SugarRepository<CrmProject> projectRepository
    ,ErpFlowUseService flowUseService
    ,ErpOperateLogService operateLogService)
    {
        _thisRepository = thisRepository;
        _outStockProductRepository = outStockProductRepository;
        _returnRepository = returnRepository;
        _produceOrderRepository = produceOrderRepository;
        _operateLogService = operateLogService;
        _flowUseService = flowUseService;
        _projectRepository = projectRepository;
    }
    
    /// <summary>
    /// 查询所有——分页
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<PageResult<ErpOutstockDto>> GetPagesAsync(PageParam param)
    {
        var query = await _thisRepository.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(param.Key),m=>m.Number.Contains(param.Key))
            .Includes(m=>m.Warehouse)
            .Includes(m=>m.Customer)
            .Includes(m=>m.Organization)
            .OrderByDescending(m=>m.Id)
            .ToPageAsync(param.Page, param.Limit);
        var result=query.Adapt<PageResult<ErpOutstockDto>>();
        
        // 销售关系，关联项目
        var projectIds = result.Items.Where(m => m.Type == ErpOutStockTypeEnum.Sales)
            .Select(m=>m.RelationId).ToList();
        if (projectIds.Any())
        {
            var projectList = await _projectRepository.GetListAsync(m => projectIds.Contains(m.Id));
            foreach (var item in result.Items.Where(m=>m.Type==ErpOutStockTypeEnum.Sales))
            {
                var projectModel = projectList.FirstOrDefault(m => m.Id == item.RelationId);
                if(projectModel==null) continue;
                item.Relation = new ErpOutStockRelationDto()
                {
                    Id = projectModel.Id,
                    Number = projectModel.Number
                };
            }
        }
        
        //生产关系
        var prduceOrderIds = result.Items.Where(m => m.Type == ErpOutStockTypeEnum.Production)
            .Select(m=>m.RelationId).ToList();
        if (prduceOrderIds.Count>0)
        {
            var produceOrderList = await _produceOrderRepository.GetListAsync(m => prduceOrderIds.Contains(m.Id));
            foreach (var item in result.Items.Where(m=>m.Type==ErpOutStockTypeEnum.Production))
            {
                var orderModel = produceOrderList.FirstOrDefault(m => m.Id == item.RelationId);
                if(orderModel==null) continue;
                item.Relation = new ErpOutStockRelationDto()
                {
                    Id = orderModel.Id,
                    Number = orderModel.Number
                };
            }
        }
        
        //采购关系
        var returnIds = result.Items.Where(m => m.Type == ErpOutStockTypeEnum.PurchaseReturn)
            .Select(m=>m.RelationId).ToList();
        if (returnIds.Count>0)
        {
            var returnList = await _returnRepository.GetListAsync(m => returnIds.Contains(m.Id));
            foreach (var item in result.Items.Where(m=>m.Type==ErpOutStockTypeEnum.PurchaseReturn))
            {
                var orderModel = returnList.FirstOrDefault(m => m.Id == item.RelationId);
                if(orderModel==null) continue;
                item.Relation = new ErpOutStockRelationDto()
                {
                    Id = orderModel.Id,
                    Number = orderModel.Number
                };
            }
        }
        return result;
    }

    /// <summary>
    /// 根据主键查询
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id}")]
    public async Task<ErpOutstockDto> GetAsync(long id)
    {
        var model = await _thisRepository.AsQueryable()
            .Includes(m=>m.Warehouse)
            .Includes(m=>m.Customer)
            .Includes(m=>m.Organization)
            .FirstAsync(m=>m.Id==id);
        var result=model.Adapt<ErpOutstockDto>();
        
        switch (model.Type)
        {
            case ErpOutStockTypeEnum.Sales:
            {
                var returnModel = await _projectRepository.GetFirstAsync(m => m.Id == model.RelationId);
                result.Relation = new ErpOutStockRelationDto()
                {
                    Id = returnModel.Id,
                    Number = returnModel.Number
                };
                break;
            }
            case ErpOutStockTypeEnum.Production:
            {
                //生产
                var produceOrderModel = await _produceOrderRepository.GetFirstAsync(m => m.Id == model.RelationId);
                result.Relation = new ErpOutStockRelationDto()
                {
                    Id = produceOrderModel.Id,
                    Number = produceOrderModel.Number
                };
            
                if (model.ApplyId!=0)
                {
                    //读取申请配置
                    var _applyRepository = _thisRepository.ChangeRepository<SugarRepository<ErpPurchaseApply>>();
                    var applyModel = await _applyRepository.GetSingleAsync(m => m.Id == model.ApplyId);
                    if (applyModel!=null)
                    {
                        result.Apply = new ErpPurchaseApplySimpleDto()
                        {
                            Id = applyModel.Id,
                            Number = applyModel.Number
                        };
                    }
                }

                break;
            }
            case ErpOutStockTypeEnum.PurchaseReturn:
            {
                var returnModel = await _returnRepository.GetFirstAsync(m => m.Id == model.RelationId);
                result.Relation = new ErpOutStockRelationDto()
                {
                    Id = returnModel.Id,
                    Number = returnModel.Number
                };
                break;
            }
        }

        result.ProductIds = await _outStockProductRepository.AsQueryable()
            .Where(m => m.OutStockId == id)
            .Select(m => m.ProductId)
            .ToListAsync();
        
        result.Flow = await _flowUseService.GetFlowAsync(model.Id);
        return result;
    }

    /// <summary>
    /// 添加
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    [UnitOfWork]
    public async Task AddAsync(ErpOutStockAddParam param)
    {
        var toDay = await _thisRepository.CountAsync(m=>SqlFunc.DateIsSame(m.CreateTime,DateTime.Now));
        param.OutStock.Number = "PO".ResNumber(toDay);
        var outStockId=await _thisRepository.InsertReturnSnowflakeIdAsync(param.OutStock.Adapt<ErpOutstock>());
        foreach (var item in param.Product)
        {
            item.OutStockId = outStockId;
            item.WarehouseId = param.OutStock.WarehouseId;
        }
        await _outStockProductRepository.InsertRangeAsync(param.Product.Adapt<List<ErpOutstockProduct>>());

        /*var productIds = new List<long>();
        // 处理采购一下逻辑
        if (param.OutStock.Type==2)
        {
            // 更改采购出库的商品状态信息
            productIds = param.Product.Select(m => m.ProductId).ToList();
            await _returnInfoRepository.UpdateAsync(m => new ErpPurchaseReturnInfo()
            {
                IsOutStock = true
            },m=>m.ReturnId==param.OutStock.RelationId && productIds.Contains(m.ProductId));
        }
        else
        {
            productIds = param.Product.Select(m => m.Id).ToList();
        }*/

        await _operateLogService.AddAsync(new ErpOperateLogDto()
        {
            OperateId = outStockId,
            Type = (int)ErpOperateEnum.OutStock,
            Remark = "创建了产品出库信息【"+param.OutStock.Number+"】"
        });
        
        if (param.OutStock.FlowId!=0)
        {
            await _flowUseService.AddAsync(new ErpFlowUseDto()
            {
                FlowId=param.OutStock.FlowId,
                UseId=outStockId,
                Type = FlowTypeEnum.OutStock,
            });
        }
    }

    /// <summary>
    /// 修改
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    [UnitOfWork]
    public async Task ModifyAsync(ErpOutStockAddParam param)
    {
        await _thisRepository.UpdateAsync(param.OutStock.Adapt<ErpOutstock>());
        await _outStockProductRepository.DeleteAsync(m => m.OutStockId == param.OutStock.Id);
        foreach (var item in param.Product)
        {
            item.OutStockId = param.OutStock.Id;
            item.WarehouseId = param.OutStock.WarehouseId;
        }
        await _outStockProductRepository.InsertRangeAsync(param.Product.Adapt<List<ErpOutstockProduct>>());

        /*var productIds = new List<long>();
        // 处理采购一下逻辑
        if (param.OutStock.Type==2)
        {
            // 更改采购出库的商品状态信息
            productIds = param.Product.Select(m => m.ProductId).ToList();
            await _returnInfoRepository.UpdateAsync(m => new ErpPurchaseReturnInfo()
            {
                IsOutStock = true
            },m=>m.ReturnId==param.OutStock.RelationId && productIds.Contains(m.ProductId));
            // 不是的，更改为非出库
            await _returnInfoRepository.UpdateAsync(m => new ErpPurchaseReturnInfo()
            {
                IsOutStock = false
            },m=>m.ReturnId==param.OutStock.RelationId && !productIds.Contains(m.ProductId));
        }
        else
        {
            productIds = param.Product.Select(m => m.Id).ToList();
        }*/
        
        //后续处理销售逻辑
        
        if (param.OutStock.Status == ErpAuditEnum.NotReviewed)
        {
            await _flowUseService.ModifyAsync(new ErpFlowUseDto()
            {
                FlowId = param.OutStock.FlowId,
                UseId = param.OutStock.Id,
                Type = FlowTypeEnum.OutStock,
            });
        }

        await _operateLogService.AddAsync(new ErpOperateLogDto()
        {
            OperateId = param.OutStock.Id,
            Type = (int)ErpOperateEnum.OutStock,
            Remark = "编辑了产品出库信息~"
        });
    }

    /// <summary>
    /// 审核状态
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    [UnitOfWork]
    public async Task ModifyStatusAsync(ErpStatusParam param)
    {
        await _thisRepository.UpdateAsync(m=>new ErpOutstock()
        {
            Status = param.Status
        },m=>m.Id==param.Ids[0]);

        if (param.Status==ErpAuditEnum.Reviewed)
        {
            var outStock = await _thisRepository.GetByIdAsync(param.Ids[0]);

            var outProductList = await _outStockProductRepository.GetListAsync(m => m.OutStockId == param.Ids[0]);
            var productIds = outProductList.Select(m => m.ProductId).ToList();
        
            #region 处理减库存操作

            var warehouseProductRepository = _thisRepository.ChangeRepository<SugarRepository<ErpWarehouseProduct>>();
            var productStockList = await warehouseProductRepository.GetListAsync(m => 
                m.WarehouseId==outStock.WarehouseId && productIds.Contains(m.ProductId));
            if (productStockList.Count==0)
            {
                throw new BusinessException("出库的产品在库存中不存在，请联系管理员~");
            }
            foreach (var item in productStockList)
            {
                var product = outProductList.FirstOrDefault(m => m.ProductId == item.ProductId);
                if (product==null)
                {
                    throw new BusinessException("产品库存中不存在，无法处理减库存业务，请联系管理员~");
                }

                if (item.Count<product.Count)
                {
                    throw new BusinessException("出库数量大于现有库存数量，无法处理业务，请联系管理员~");
                }

                item.Count -= product.Count;
            }
            await warehouseProductRepository.UpdateRangeAsync(productStockList);
            #endregion
        }
        
        if (param.Status==ErpAuditEnum.InReview)
        {
            foreach (var item in param.Ids)
            {
                await _flowUseService.StartAuditAsync(item, FlowTypeEnum.OutStock);
            }
        }
        
        await _operateLogService.AddAsync(new ErpOperateLogDto()
        {
            OperateId = param.Ids[0],
            Type = (int)ErpOperateEnum.PurchaseOrder,
            Remark = "对产品出库做了审核"+param.Status.GetDescription()+"操作"
        });
    }

    /// <summary>
    /// 删除,支持批量
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    [HttpDelete,UnitOfWork]
    public async Task DeleteAsync([FromBody] List<long> ids)
    {
        await _thisRepository.DeleteAsync(m=>ids.Contains(m.Id));
        await _outStockProductRepository.DeleteAsync(m => ids.Contains(m.OutStockId));
        await _flowUseService.DeleteAsync(ids);
    }
}
